﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TankController.Dominio;

namespace TankController
{
    public partial class FormControleTipoA : FormControle, IFormControle
    {
        //private FormPrincipal formPrincipal;

        public FormControleTipoA(FormPrincipal formPrincipal)
            : base(formPrincipal)
        {
            InitializeComponent();

            //this.formPrincipal = formPrincipal;
        }

        private void FormControle_Shown(object sender, EventArgs e)
        {
            AtualizarCampos();
        }

        public void AtualizarCampos()
        {
            AtualizarCamposEntrada();
            AtualizarCamposControlador();

            btnPlay.Focus();
        }

        private void AtualizarCamposEntrada()
        {
            if (Global.Controlador1 is ControladorMalhaFechada)
            {
                lblEntrada.Text = "Degrau";
                txtEntrada.Text = ((Global.Controlador1 as ControladorMalhaFechada).Referencia as EntradaDegrau).ValorAmplitude.ToString();
            }
            else
            {
                IEntrada entrada = (Global.Controlador1 as ControladorMalhaAberta).Entrada;

                if (entrada is EntradaDegrau)
                {
                    lblEntrada.Text = "Degrau";
                    txtEntrada.Text = (entrada as EntradaDegrau).ValorAmplitude.ToString();
                }
                else if (entrada is EntradaPeriodica)
                {
                    if (entrada is EntradaSenoidal)
                    {
                        lblEntrada.Text = "Onda Senoidal";
                    }
                    else if (entrada is EntradaQuadrada)
                    {
                        lblEntrada.Text = "Onda Quadrada";
                    }
                    else if (entrada is EntradaDenteSerra)
                    {
                        lblEntrada.Text = "Onda Dente-de-Serra";
                    }
                    else
                    {
                        throw new ApplicationException("Tipo de entrada periódica inválida.");
                    }

                    txtEntrada.Text = (entrada as EntradaPeriodica).AmplitudeMaxima.ToString();
                }
                else
                {
                    throw new ApplicationException("Tipo de entrada inválida.");
                }
            }
        }

        public void AtualizarCamposControlador()
        {
            lblControlador.Text = Global.Controlador1.Descricao;

            if (Global.Controlador1 is ControladorMalhaFechada)
            {
                if (Global.Controlador1 is ControladorDefaultMalhaFechada)
                {
                    gbxAcoes.Enabled = false;

                    pnlAcaoProporcional.Enabled = false;
                    pnlAcaoIntegral.Enabled = false;
                    pnlAcaoDerivativa.Enabled = false;
                }
                else if (Global.Controlador1 is ControladorP)
                {
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = false;
                    pnlAcaoDerivativa.Enabled = false;

                    txtKp.Text = (Global.Controlador1 as ControladorP).Kp.ToString();
                }
                else if (Global.Controlador1 is ControladorPI)
                {
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = true;
                    pnlAcaoDerivativa.Enabled = false;

                    txtKp.Text = (Global.Controlador1 as ControladorPI).Kp.ToString();

                    if (Global.ConfiguraKi1)
                    {
                        rbtKi.Checked = true;
                        txtTi.Text = "";
                        txtKi.Text = (Global.Controlador1 as ControladorPI).Ki.ToString();
                    }
                    else
                    {
                        rbtTi.Checked = true;
                        txtKi.Text = "";
                        txtTi.Text = (1 / (Global.Controlador1 as ControladorPI).Ki).ToString();
                    }
                }
                else if (Global.Controlador1 is ControladorPD)
                {
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = false;
                    pnlAcaoDerivativa.Enabled = true;

                    txtKp.Text = (Global.Controlador1 as ControladorPD).Kp.ToString();
                    
                    if (Global.ConfiguraKd1)
                    {
                        rbtKd.Checked = true;
                        txtTd.Text = "";
                        txtKd.Text = (Global.Controlador1 as ControladorPD).Kd.ToString();
                    }
                    else
                    {
                        rbtTd.Checked = true;
                        txtKd.Text = "";
                        txtTd.Text = (1 / (Global.Controlador1 as ControladorPD).Kd).ToString();
                    }
                }
                else if (Global.Controlador1 is ControladorPID)
                {
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = true;
                    pnlAcaoDerivativa.Enabled = true;

                    txtKp.Text = (Global.Controlador1 as ControladorPID).Kp.ToString();

                    if (Global.ConfiguraKi1)
                    {
                        rbtKi.Checked = true;
                        txtKi.Text = (Global.Controlador1 as ControladorPID).Ki.ToString();
                        txtTi.Text = "";
                    }
                    else
                    {
                        rbtTi.Checked = true;
                        txtKi.Text = "";
                        txtTi.Text = (1 / (Global.Controlador1 as ControladorPID).Ki).ToString();
                    }

                    if (Global.ConfiguraKd1)
                    {
                        rbtKd.Checked = true;
                        txtKd.Text = (Global.Controlador1 as ControladorPID).Kd.ToString();
                        txtTd.Text = "";
                    }
                    else
                    {
                        rbtTd.Checked = true;
                        txtKd.Text = "";
                        txtTd.Text = (1 / (Global.Controlador1 as ControladorPID).Kd).ToString();
                    }
                }
                else if (Global.Controlador1 is ControladorPI_D)
                {
                    gbxAcoes.Enabled = true;

                    pnlAcaoProporcional.Enabled = true;
                    pnlAcaoIntegral.Enabled = true;
                    pnlAcaoDerivativa.Enabled = true;

                    txtKp.Text = (Global.Controlador1 as ControladorPI_D).Kp.ToString();

                    if (Global.ConfiguraKi1)
                    {
                        rbtKi.Checked = true;
                        txtKi.Text = (Global.Controlador1 as ControladorPI_D).Ki.ToString();
                        txtTi.Text = "";
                    }
                    else
                    {
                        rbtTi.Checked = true;
                        txtKi.Text = "";
                        txtTi.Text = (1 / (Global.Controlador1 as ControladorPI_D).Ki).ToString();
                    }

                    if (Global.ConfiguraKd1)
                    {
                        rbtKd.Checked = true;
                        txtKd.Text = (Global.Controlador1 as ControladorPI_D).Kd.ToString();
                        txtTd.Text = "";
                    }
                    else
                    {
                        rbtTd.Checked = true;
                        txtKd.Text = "";
                        txtTd.Text = (1 / (Global.Controlador1 as ControladorPI_D).Kd).ToString();
                    }
                }
                else
                {
                    throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
                }
            }
            else
            {
                gbxAcoes.Enabled = false;
            }
        }

        private void MontarEntrada()
        {
            double amplitude = double.Parse(txtEntrada.Text.Replace('.', ','));

            if (IsMalhaFechada())
            {
                EntradaDegrau referencia = ((Global.Controlador1 as ControladorMalhaFechada).Referencia as EntradaDegrau);

                if (amplitude != referencia.ValorAmplitude)
                {
                    formPrincipal.AtualizarReferencia();
                }

                referencia.ValorAmplitude = amplitude;
            }
            else
            {
                IEntrada entrada = (Global.Controlador1 as ControladorMalhaAberta).Entrada;

                if (entrada is EntradaDegrau)
                {
                    if (amplitude != (entrada as EntradaDegrau).ValorAmplitude)
                    {
                        formPrincipal.AtualizarReferencia();
                    }

                    (entrada as EntradaDegrau).ValorAmplitude = amplitude;
                }
                else if (entrada is EntradaPeriodica)
                {
                    if (amplitude != (entrada as EntradaPeriodica).AmplitudeMaxima)
                    {
                        formPrincipal.AtualizarReferencia();
                    }

                    (entrada as EntradaPeriodica).AmplitudeMaxima = amplitude;
                }
                else
                {
                    throw new ApplicationException("Tipo de entrada inválida.");
                }
            }
        }

        private void MontarControlador()
        {
            if (IsMalhaFechada())
            {
                double kp = 0;
                double ki = 0;
                double kd = 0;

                if (Global.Controlador1 is ControladorDefaultMalhaFechada)
                {

                }
                else if (Global.Controlador1 is ControladorP)
                {
                    kp = double.Parse(txtKp.Text.Replace('.', ','));

                    (Global.Controlador1 as ControladorP).SetGanho(kp);
                }
                else if (Global.Controlador1 is ControladorPI)
                {
                    kp = double.Parse(txtKp.Text.Replace('.', ','));
                    ki = rbtKi.Checked ? double.Parse(txtKi.Text.Replace('.', ',')) : 1 / double.Parse(txtTi.Text.Replace('.', ','));

                    (Global.Controlador1 as ControladorPI).SetGanho(kp, ki);
                }
                else if (Global.Controlador1 is ControladorPD)
                {
                    kp = double.Parse(txtKp.Text.Replace('.', ','));
                    kd = rbtKd.Checked ? double.Parse(txtKd.Text.Replace('.', ',')) : 1 / double.Parse(txtTd.Text.Replace('.', ','));

                    (Global.Controlador1 as ControladorPD).SetGanho(kp, kd);
                }
                else if (Global.Controlador1 is ControladorPID)
                {
                    kp = double.Parse(txtKp.Text.Replace('.', ','));
                    ki = rbtKi.Checked ? double.Parse(txtKi.Text) : 1 / double.Parse(txtTi.Text.Replace('.', ','));
                    kd = rbtKd.Checked ? double.Parse(txtKd.Text) : 1 / double.Parse(txtTd.Text.Replace('.', ','));

                    (Global.Controlador1 as ControladorPID).SetGanho(kp, ki, kd);
                }
                else if (Global.Controlador1 is ControladorPI_D)
                {
                    kp = double.Parse(txtKp.Text.Replace('.', ','));
                    ki = rbtKi.Checked ? double.Parse(txtKi.Text.Replace('.', ',')) : 1 / double.Parse(txtTi.Text.Replace('.', ','));
                    kd = rbtKd.Checked ? double.Parse(txtKd.Text.Replace('.', ',')) : 1 / double.Parse(txtTd.Text.Replace('.', ','));

                    (Global.Controlador1 as ControladorPI_D).SetGanho(kp, ki, kd);
                }
                else
                {
                    throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
                }
            }
            else
            {

            }
        }

        private Boolean IsMalhaFechada()
        {
            return Global.Controlador1 is ControladorMalhaFechada;
        }

        private void btnPlay_Click(object sender, EventArgs e)
        {
            try
            {
                ValidarCampos();

                MontarEntrada();
                MontarControlador();

                formPrincipal.Play();

                btnPlay.Enabled = false;
                btnPause.Enabled = true;
                btnStop.Enabled = true;
                gbxControlador.Enabled = false;
                lklMudarEntrada.Enabled = false;
            }
            catch (ApplicationException apex)
            {
                MessageBox.Show(apex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnPause_Click(object sender, EventArgs e)
        {

        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            formPrincipal.Stop();

            btnPlay.Enabled = true;
            btnPause.Enabled = false;
            btnStop.Enabled = false;
            gbxControlador.Enabled = true;
            lklMudarEntrada.Enabled = true;
        }

        private void ValidarCampos()
        {
            double parseResult;

            if (!double.TryParse(txtEntrada.Text.Replace('.', ','), out parseResult))
            {
                throw new ApplicationException("Valor de amplitude/referência inválido.");
            }

            if (IsMalhaFechada())
            {
                if (!(Global.Controlador1 is ControladorDefaultMalhaFechada) &&
                    !double.TryParse(txtKp.Text.Replace('.', ','), out parseResult))
                {
                    throw new ApplicationException("Valor de Kp inválido.");
                }

                if ((Global.Controlador1 is ControladorPI ||
                    Global.Controlador1 is ControladorPID ||
                    Global.Controlador1 is ControladorPI_D) &&
                    rbtKi.Checked && !double.TryParse(txtKi.Text.Replace('.', ','), out parseResult))
                {
                    throw new ApplicationException("Valor de Ki inválido.");
                }

                if ((Global.Controlador1 is ControladorPI ||
                    Global.Controlador1 is ControladorPID ||
                    Global.Controlador1 is ControladorPI_D) &&
                    rbtTi.Checked && !double.TryParse(txtTi.Text.Replace('.', ','), out parseResult))
                {
                    throw new ApplicationException("Valor de Ti inválido.");
                }

                if ((Global.Controlador1 is ControladorPD ||
                    Global.Controlador1 is ControladorPID ||
                    Global.Controlador1 is ControladorPI_D) &&
                    rbtKd.Checked && !double.TryParse(txtKd.Text.Replace('.', ','), out parseResult))
                {
                    throw new ApplicationException("Valor de Kd inválido.");
                }

                if ((Global.Controlador1 is ControladorPD ||
                    Global.Controlador1 is ControladorPID ||
                    Global.Controlador1 is ControladorPI_D) &&
                    rbtTd.Checked && !double.TryParse(txtTd.Text.Replace('.', ','), out parseResult))
                {
                    throw new ApplicationException("Valor de Td inválido.");
                }
            }
        }

        private void rbtAcaoIntegrativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKi.Checked)
            {
                txtKi.Enabled = true;
                txtTi.Enabled = false;

                rbtKd.Checked = true;

                Global.ConfiguraKi1 = true;
            }
            else
            {
                txtKi.Enabled = false;
                txtTi.Enabled = true;

                rbtTd.Checked = true;

                Global.ConfiguraKi1 = false;
            }
        }

        private void rbtAcaoDerivativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKd.Checked)
            {
                txtKd.Enabled = true;
                txtTd.Enabled = false;

                rbtKi.Checked = true;

                Global.ConfiguraKd1 = true;
            }
            else
            {
                txtKd.Enabled = false;
                txtTd.Enabled = true;

                rbtTi.Checked = true;

                Global.ConfiguraKd1 = false;
            }
        }

        private void lklSelecionarControlador_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            MostrarTelaConfigurar(TipoAba.Controlador1);
        }

        private void lklMudarEntrada_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            MostrarTelaConfigurar(TipoAba.Entrada);
        }

        private void FormControle_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (Global.Status == Status.Play || Global.Status == Status.Pause)
            {
                e.Cancel = true;

                MessageBox.Show("Não é possível fechar a janela com o sistema em execução.", "ERRO", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void txtParametro_KeyPress(object sender, KeyPressEventArgs e)
        {
            try
            {
                if (e.KeyChar == (char)Keys.Return)
                {
                    ValidarCampos();

                    MontarEntrada();
                    MontarControlador();

                    e.Handled = true;
                }
            }
            catch (ApplicationException apex)
            {
                MessageBox.Show(apex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}
